function outvar = subsref(htio, S)
% transio::subsref  - overloaded method
%
% transio(I)       - values at position(s) I
% transio(XI, YI)  - values at position(s) XI, YI
% transio(end, YI) - values at position(s) size(transio, 1), YI

% Version:  v0.7g
% Build:    9101517
% Date:     Oct-15 2009, 5:22 PM CEST
% Author:   Jochen Weber, SCAN Unit, Columbia University, NYC, NY, USA
% URL/Info: http://wiki.brainvoyager.com/BVQXtools

% argument check
if nargin < 2
    error( ...
        'transio:BadSubsRef', ...
        'No S subsref struct given.' ...
    );
end

% get datatype and type size for access functions
csn = ['*' htio.DataType];
csz = htio.TypeSize;
siz = htio.DataDims;

% parse S
try

    % use external function to efficiently get indices
    [ots, idx, ridx, cidx, lastcol] = ioidx(S, siz);
    pots = prod(ots);
    if length(ots) > length(siz)
        cpr = [1, cumprod(ots)]';
    else
        cpr = [1, cumprod(siz)]';
    end
    lsz = length(idx);
    lsx = lsz + 1;
    if length(cpr) > lsx
        cpr = cpr(1:lsx);
    end
catch
    error( ...
        'transio:BadSubsRef', ...
        'Invalid S subsref struct given: ''%s''.', ...
        lasterr ...
    );
end

% initialize output to class
outvar = eval([csn(2:end) '(0)']);

% return empty if nothing is to be read
if pots < 1
    outvar(1) = [];
    outvar = reshape(outvar, ots);
    return;
end

% open file and check
try
    if htio.LittleND
        fid = fopen(htio.FileName, 'rb', 'ieee-le');
    else
        fid = fopen(htio.FileName, 'rb', 'ieee-be');
    end
catch
    fid = 0;
end
if fid < 1
    error( ...
        'transio:FileNotOpen', ...
        'Error opening file: ''%s''.', ...
        htio.FileName ...
    );
end

% get offset within file
ofs = htio.IOOffset;

% take specific care of one length arguments
if lsz == 1

    % treat singular-index input
    idx = idx{1};

    % character index
    if ischar(idx)

        % go to position
        try
            fseek(fid, ofs, -1);
            outvar = fread(fid, [pots, 1], csn);
        catch
            fclose(fid);
            error( ...
                'transio:FileReadError', ...
                'Error reading array(:) from file.' ...
            );
        end
        fclose(fid);
        return;
    end

    % if contiguous
    if length(cidx{1}) < 3

        % try read
        try
            fseek(fid, ofs + csz * (idx(1) - 1), -1);
            outvar = reshape(fread(fid, [pots, 1], csn), ots);
        catch
            fclose(fid);
            error( ...
                'transio:FileReadError', ...
                'Error reading array part from file.' ...
            );
        end

    % otherwise
    else

        % initialize output
        outvar(pots) = outvar(1);
        outvar = reshape(outvar, ots);

        % get cidx for fast access
        cidx = cidx{1};

        % then ...
        try

            % read as long as breaks are found
            dsz = cidx(1);
            for bc = 1:(length(cidx) - 1)

                % get position of break
                dsz2 = cidx(bc + 1);

                % go to position in file
                fseek(fid, ofs + csz * (idx(dsz) - 1), -1);

                % read as much as needed
                outvar(dsz:(dsz2 - 1)) = fread(fid, [dsz2 - dsz, 1], csn);

                % and copy old break to new start
                dsz = dsz2;
            end

        catch
            error( ...
                'transio:FileReadError', ...
                'Error reading array part from file.' ...
            );
        end
    end

    % close file
    fclose(fid);

    % reorder indices if needed
    if ~ischar(ridx{1})
        outvar = reshape(outvar(ridx{1}), ots);
    end

    % return now
    return;

% all are :
elseif lastcol == lsz

    % go to first index and read entire array
    try
        fseek(fid, ofs, -1);
        outvar = reshape(fread(fid, [pots, 1], csn), ots);
    catch
        fclose(fid);
        error( ...
            'transio:FileReadError', ...
            'Error reading array(:,...,:) from file.' ...
        );
    end

    % close file and keep track of it!
    fclose(fid);
    fid = 0;

% all but last are colon and last is contiguous
elseif lastcol == (lsz - 1) && ...
    length(cidx{end}) < 3

    % go to first index and read entire array
    try
        fseek(fid, ofs + csz * (idx{end}(1) - 1) * cpr(end - 1), -1);
        outvar = reshape(fread(fid, [pots, 1], csn), ots);
    catch
        fclose(fid);
        error( ...
            'transio:FileReadError', ...
            'Error reading array(:,...,I) from file.' ...
        );
    end

    % close file and keep track of it!
    fclose(fid);
    fid = 0;
end

% reordering indices
rS.type = '()';
rS.subs = cell(1, lsz);
userS = false;
for bc = 1:lsz
    rS.subs{bc} = ridx{bc};
    if ~ischar(ridx{bc})
        userS = true;
    end
end

% something has been read already
if fid < 1

    % apply reordering
    if userS
        outvar = reshape(subsref(outvar, rS), ots);
    end

    % return now
    return;
end

% we have true multiple indexing, so initialize output now at the latest
outvar(pots) = outvar(1);
outvar = reshape(outvar, ots);

% rebuilt S
rds = ots;
ofc = ones(1, lsx);
otc = ones(1, lsx);
otf = ones(1, lsx);
S = struct;
S.type = '()';
S.subs = {':'};
rcol = lastcol + 1;
for cc = 1:lsz
    if cc < rcol
        S.subs{cc} = ':';
    else
        S.subs{cc} = 1;
        ofc(cc) = idx{cc}(1);

        % set final block counter
        if length(cidx{cc}) > 1
            otf(cc) = length(cidx{cc}) - 1;
        else
            otf(cc) = length(idx{cc});
        end
        rds(cc) = 1;
    end
end

% read specific parts
cidx = cidx{rcol};
cpsiz = cpr(rcol);
while otc(end) < 2

    % find position
    rpos = ofs + csz * (ofc - 1) * cpr;

    % which indices to read next
    rstr = cidx(otc(rcol)):(cidx(otc(rcol)+1)-1);
    S.subs{rcol} = rstr;

    % number of indices
    rsiz = length(rstr);

    % set into reshape array
    rds(rcol) = rsiz;

    % calculate number of elements
    rdp = cpsiz * rsiz;

    % try to read and directly store in outvar
    try
        fseek(fid, rpos, -1);
        subsasgn(outvar, S, reshape(fread(fid, [rdp, 1], csn), rds));
    catch
        fclose(fid);
        error( ...
            'transio:FileReadError', ...
            'Error reading array part from file.' ...
        );
    end

    % start with rcol
    cc = rcol;

    % and go on until last column reaches
    while cc <= lsx

        % increase block count
        otc(cc) = otc(cc) + 1;

        % more blocks to come for this dim?
        if otc(cc) <= otf(cc)

            % increase non-contiguous counter only for later dims
            if cc > rcol
                S.subs{cc} = S.subs{cc} + 1;
            end

            % reset ofc
            if cc == rcol
                ofc(cc) = idx{cc}(cidx(otc(cc)));
            else
                ofc(cc) = idx{cc}(otc(cc));
            end

            % go on ...
            break;

        % last column (termination criterion)
        elseif cc > lsz

            % means: leave reading loop!
            break;
        end

        % set block counter for cc to 1
        otc(cc) = 1;

        % and also set subs structure
        S.subs{cc} = 1;

        % and ofc
        ofc(cc) = idx{cc}(1);

        % then increase column counter
        cc = cc + 1;
    end
end

% close file !!
fclose(fid);

% reorder indices for rcol ?
if userS
    outvar = reshape(subsref(outvar, rS), ots);
end
